package stub;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import messages.BaseMessage;
import messages.DeregistrationMessage;
import messages.MessageType;
import messages.registration.ElevatorRegistrationMessageAck;
import messages.elevator.ElevatorStatusMessage;
import messages.elevator.ElevatorStatusRequest;
import messages.MessageFactory;

public class GDispatcherStub {
	private ServerSocket sSocket;
	private Socket socket;
	
	
	public GDispatcherStub(int port){
		try {
			sSocket = new ServerSocket(port);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	//Open the socket, and ensure that it actually opened
	public boolean openSocket(){
		try {
			socket = sSocket.accept();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return !socket.isClosed();
	}
	
	
	//Close the socket and be sure that it actually closed
	public boolean closeSocket(){
		try {
			socket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return socket.isClosed();
	}
	
	//Check to see if the socket is closed 
	//(Ie after an elevator was deregistered)
	public boolean isSocketClosed(){
		return socket.isClosed();
	}
	
	//Receive an incoming registration message
	public boolean getRegistration(){
	    BaseMessage m = null;
		
		try {
			m = MessageFactory.readMessage(socket);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return m.getMessageType()==MessageType.ElevatorRegistrationMessage;
	}
	
	
	//Send a registration reply, and expect an elevator status response
	public boolean sendRegistrationReply(byte clientId, byte maxFloors){
	    BaseMessage m = null;
	    
	    m=new ElevatorRegistrationMessageAck(clientId,maxFloors);
		
	    //Write the registration message ack
	    try {
			socket.getOutputStream().write(m.toByteArray());
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	    
	    try {
			m=MessageFactory.readMessage(socket);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//We are expecting a status message
		return (m.getMessageType()==MessageType.ElevatorStatusMessage);

	}
	
	
	//Send a status request, and expect a status message response
	public boolean pingElevator(){
	    BaseMessage m = null;
	    m=new ElevatorStatusRequest();
	      
	    //Write the status request
	    try {
			socket.getOutputStream().write(m.toByteArray());
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		//Read the incoming message
		try {
			m=MessageFactory.readMessage(socket);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//We are expecting a status message
		return m.getMessageType()==MessageType.ElevatorStatusMessage;
	}
	
	
	//Check to see if the elevator id matches the provided one
	public boolean checkId(byte clientId){
	    BaseMessage m = null;
	    ElevatorStatusMessage esm;
	    
	    m=new ElevatorStatusRequest();
		
	    //Write the registration message ack
	    try {
			socket.getOutputStream().write(m.toByteArray());
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	    
	    try {
			m=MessageFactory.readMessage(socket);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//We are expecting a status message
		if (m.getMessageType()!=MessageType.ElevatorStatusMessage){
			return false;
		}else{
			esm = (ElevatorStatusMessage) m;
			return esm.getElevatorStruct().identifier==clientId;
		}
	}
	
	//Send a deregistration message to the elevator, and check 
	//to see if the socket is closed afterwards.
	public boolean deregisterElevator(){
	    BaseMessage m = null;
	    m=new DeregistrationMessage();
	      
	    //Write the deregistration
	    try {
			socket.getOutputStream().write(m.toByteArray());
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	
	    
	    closeSocket();
		
		//The elevator should be done now
		return socket.isClosed();
	}

	public InetAddress getElevatorAddress(){
		return socket.getInetAddress();
	}
	
	//Get the port opened by the elevator for UDP
	//communications
	public int getElevatorUDPPort(){
	    BaseMessage m = null;
	    ElevatorStatusMessage esm;
	    m=new ElevatorStatusRequest();
	    
	      
	    //Write the status request
	    try {
			socket.getOutputStream().write(m.toByteArray());
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		//Read the incoming message
		try {
			m=MessageFactory.readMessage(socket);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//We are expecting a status message
		esm = (ElevatorStatusMessage) m;
		return esm.getElevatorStruct().udpPort;
	}
	
}
